#ifndef _FIFO_H_
#define _FIFO_H_

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>


#ifndef __fifo_malloc
#define __fifo_malloc malloc
#endif

#ifndef __fifo_free
#define __fifo_free   free
#endif

#if 0
#ifndef __fifo_realloc
#define __fifo_realloc realloc
#endif
#endif

#define FIFO_MEMSIZE (1024 * 4 * 16)

typedef struct __fifo_s fifo_t;

struct __fifo_s {
    char *mem;
    char *mem_tail;
    int   mem_size;

    union {
        char *front;
        char *buf;
    };
    char *rear;
    int len;

    int (*flush)(fifo_t *f);
    void *private_data;
};

static int fifo_init(fifo_t *f, int mem_size, int (*flush)(fifo_t *f))
{
    int size = (mem_size < FIFO_MEMSIZE) ? FIFO_MEMSIZE : ((mem_size + 4096 - 1) / 4096) * 4096;

    char *mem = (char *)__fifo_malloc(size);
    if (mem == NULL)
        return -1;

    memset(mem, 0, size);

    f->mem = mem;
    f->mem_size = size;
    f->mem_tail = f->mem + f->mem_size;

    f->front = f->mem;
    f->rear = f->front;
    f->len = 0;

    return 0;
}

static void fifo_deinit(fifo_t *f)
{
    if (f->flush) {
        while(f->flush(f) > 0);
    }
    memset(f->mem, 0, f->mem_size);
    free(f->mem);
    memset(f, 0, sizeof(*f));
}

static void fifo_move(fifo_t *f)
{
    if (f->front != f->mem) {
        memmove(f->mem, f->front, f->len);
        f->front = f->mem; // not do move twice
        f->rear = f->front + f->len;
    }
}

static void fifo_flush(fifo_t *f)
{
}

static int fifo_add(fifo_t *f, const char *data, int n)
{
do_copy:
    // copy
    if (f->rear - f->mem_tail >= n) {
        memcpy(f->rear, data, n);
        f->rear += n;
        f->len += n;
        return 0;
    }

    // move

    return 0;
}

static int fifo_del(fifo_t *f, int n)
{
    if (f->len >= n) {
        f->front -= n;
        f->len -= n;
        return 0;
    }

    return -1;
}

#if 0
int main()
{

    fifo_t out;
    fifo_init(&out, 0, NULL);
}
#endif

#endif


